package vt.transit.server.services;

import java.sql.Connection;
import java.sql.DriverManager;
import java.util.List;

import org.apache.log4j.Logger;

import vt.transit.server.data.BusStop;
import vt.transit.server.data.BusStopCrime;
import vt.transit.server.data.CrimeInstance;
import vt.transit.server.data.MetroStop;
import vt.transit.server.data.MetroStopCrime;
import vt.transit.server.data.access.BusStopService;
import vt.transit.server.data.access.CrimeInstanceService;
import vt.transit.server.data.access.MetroStopService;

public class MobileServicesImpl implements MobileServices {
	
	private static Logger logger = Logger.getLogger(MobileServicesImpl.class);
	
	public static final String POSTGIS_DRIVER = "org.postgis.DriverWrapper";
	public static final String POSTGIS_PROTOCOL = "jdbc:postgresql_postGIS://";

	private String databaseHost;
	private int databasePort;
	private String database;
	private String username;
	private String password;
		
	private Connection connectToDB() {
		Connection conn = null;

		try {
			Class.forName(POSTGIS_DRIVER);
			conn = DriverManager.getConnection(
					POSTGIS_PROTOCOL + databaseHost + ":" + databasePort + "/" + database,
				     username,
				     password );
		} catch (Exception e) {
			logger.error("Exception connecting to DB", e);
			return null;
		} 
		
		return conn;
	}
	
	public String test() {
		return "test";
	}
	
	@Override
	public int getNumCrimes() {
		Connection conn = connectToDB();
		
		int numCrimes = 0;
		
		try {
			// get a count of all crimes within 200 m of metro stop "A03" (Dupont Circle)
			numCrimes = CrimeInstanceService.getNumberOfCrimes(conn, "A03", 200);
			logger.info(numCrimes);
			
			
			/*Statement st = conn.createStatement();
			ResultSet rs = st.executeQuery("SELECT location::geometry AS geom FROM crime WHERE gid=35");
			while (rs.next()) {		

				PGgeometry object = (PGgeometry) rs.getObject(1);
				logger.info(object.getType());
				
				if (object.getGeoType() == Geometry.POINT) {
					Point point = (Point)object.getGeometry();
					result.append(point.x + " " + point.y);
				}
			}
			rs.close();
			st.close();*/
			
		} finally {
			try { 
				conn.close(); 
			} catch (Exception e) { 
				logger.error("Exception while closing connection", e);
			}
		}
			
		return numCrimes;
	}
	
	@Override
	public List<CrimeInstance> getAllCrimeInstances() {
		Connection conn = connectToDB();
		
		List<CrimeInstance> crimeInstances = null;
		try {
			// get all crimes within 200 m of metro stop "A03" (Dupont Circle)			
			crimeInstances = CrimeInstanceService.getAllCrimes(conn, "A03", 200);
		} finally {
			try { 
				conn.close(); 
			} catch (Exception e) { 
				logger.error("Exception while closing connection", e);
			}
		}
			
		return crimeInstances;
	}
	

	@Override
	public List<CrimeInstance> getAllCrimesNearby(double lat, double lon, double radius) {
		Connection conn = connectToDB();
		
		List<CrimeInstance> crimeInstances = null;
		try {
			// get all crimes within some distance of this lat, lon	
			crimeInstances = CrimeInstanceService.getAllCrimes(conn, lat, lon, radius);
		} finally {
			try { 
				conn.close(); 
			} catch (Exception e) { 
				logger.error("Exception while closing connection", e);
			}
		}
		
		return crimeInstances;
	}
	
	@Override
	public List<MetroStop> getAllMetroStopsNearby(double lat, double lon,
			double radius) {
		Connection conn = connectToDB();
		
		List<MetroStop> metroStops = null;
		try {
			// get all crimes within some distance of this lat, lon	
			metroStops = MetroStopService.getAllMetroStopsNearby(conn, lat, lon, radius);
		} finally {
			try { 
				conn.close(); 
			} catch (Exception e) { 
				logger.error("Exception while closing connection", e);
			}
		}
		
		return metroStops;
	}

	@Override
	public List<BusStop> getAllBusStopsNearby(double lat, double lon,
			double radius) {
		Connection conn = connectToDB();
		
		List<BusStop> busStops = null;
		try {
			// get all crimes within some distance of this lat, lon	
			busStops = BusStopService.getAllBusStopsNearby(conn, lat, lon, radius);
		} finally {
			try { 
				conn.close(); 
			} catch (Exception e) { 
				logger.error("Exception while closing connection", e);
			}
		}
		
		return busStops;
	}
	

	@Override
	public List<MetroStopCrime> getRailCrimeStats(double lat, double lon, int count) {
		Connection conn = connectToDB();
		
		List<MetroStopCrime> metroStopCrimes = null;
		try {
			// get crime stats for the closest metro stops
			metroStopCrimes = MetroStopService.getMetroStopsAndCrimeNearby(conn, lat, lon, count);
		} finally {
			try { 
				conn.close(); 
			} catch (Exception e) { 
				logger.error("Exception while closing connection", e);
			}
		}
		
		return metroStopCrimes;
	}
	

	@Override
	public List<BusStopCrime> getBusCrimeStats(double lat, double lon, int count) {
		Connection conn = connectToDB();
		
		List<BusStopCrime> busStopCrimes = null;
		try {
			// get crime stats for the closest bus stops 
			busStopCrimes = BusStopService.getBusStopsAndCrimeNearby(conn, lat, lon, count);
		} finally {
			try { 
				conn.close(); 
			} catch (Exception e) { 
				logger.error("Exception while closing connection", e);
			}
		}
		
		return busStopCrimes;
	}

	public void setDatabaseHost(String databaseHost) {
		this.databaseHost = databaseHost;
	}

	public void setDatabasePort(int databasePort) {
		this.databasePort = databasePort;
	}
	
	public void setUsername(String username) {
		this.username = username;
	}

	public void setPassword(String password) {
		this.password = password;
	}

	public void setDatabase(String database) {
		this.database = database;
	}



}
